package cn.zbzcode.hrm.service.impl;

import cn.zbzcode.hrm.config.ImageCodeProperties;
import cn.zbzcode.hrm.dto.SendSMSDto;
import cn.zbzcode.hrm.feign.client.RedisFeignClient;
import cn.zbzcode.hrm.service.IVerifyCodeService;
import cn.zbzcode.hrm.utils.AjaxResult;
import cn.zbzcode.hrm.utils.HttpUtil;
import cn.zbzcode.hrm.utils.StrUtils;
import cn.zbzcode.hrm.utils.VerifyCodeUtils;
import cn.zbzcode.hrm.vo.SendSmsCodeVo;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisFeignClient redisFeignClient ;

    @Autowired
    private ImageCodeProperties imageCodeProperties;

    @Override
    public String creatImageCode(String imageKey) {

        //1.参数判断
        if(StringUtils.isBlank(imageKey)){
            throw new RuntimeException("无效的验证码KEY");
        }

        //2.后端接收到imageKey,后端需要生成图片验证码的值：xoxo
        String imageValue = UUID.randomUUID().toString().substring(0,imageCodeProperties.getLength());

        //3.把这个图片验证码的值存储到Redis,要以前端传入的key去存：  imageKey=xoxo
        //并且设置过期时间
        AjaxResult imageCodeResult = redisFeignClient.setex(imageKey, imageCodeProperties.getTimeout(), imageValue);

        if(!imageCodeResult.isSuccess()){
            throw new RuntimeException("图片验证码创建失败");
        }

        //4.把图片验证码的值：xoxo合并到一个图片
        String imageCodeBase64Str = VerifyCodeUtils.verifyCode(
                imageCodeProperties.getWidth(),
                imageCodeProperties.getHeight(),
                imageValue);

        //4.把图片基于Base64编码层字符串，响应给前端
        return imageCodeBase64Str ;
    }

    @Override
    public void sendSmsCode(SendSMSDto sendSMSDto) {
        //1.基本参数获取和非空判断
        //拿到用户输入的图片验证码
        String imageCode = sendSMSDto.getImageCode();
        //拿到图片验证码的key
        String imageCodeKey = sendSMSDto.getImageCodeKey();
        //拿到手机号
        String mobile = sendSMSDto.getMobile();
        //拿到的数据非空判断
        if(StringUtils.isBlank(imageCodeKey) || StringUtils.isBlank(imageCode) || StringUtils.isBlank(mobile)){
            throw new RuntimeException("无效的手机验证码或图片验证码");
        }

        //2.后端判断图片验证码是否正确 ：redis中的和传入的比较
        //从redis中拿到图片验证码
        AjaxResult ajaxResult = redisFeignClient.get(imageCodeKey);
        if(!ajaxResult.isSuccess() || ajaxResult.getResultObj() == null){
            throw new RuntimeException("无效的图片验证码,请重新填写");
        }
        //把验证码转换为字符串，方便比较
        String imgeCodeFromRedis = ajaxResult.getResultObj().toString();
        if(!imgeCodeFromRedis.toLowerCase().equals(imageCode.toLowerCase())){
            throw new RuntimeException("图片验证码错误,请重新填写");
        }

        //3.后端判断Redis是否已经有一个有效的短信验证码
        String smsCodeKey ="REGISTER:SMS:"+mobile;
        //当前发送短信验证码时间
        Date now = new Date( );
        String smsCodeValue = null;
        //从redis获取上一次的验证码的记录，看是否已经存在验证码
        AjaxResult smsCodelLastAjaxResult = redisFeignClient.get(smsCodeKey);
        if(smsCodelLastAjaxResult.isSuccess() && smsCodelLastAjaxResult.getResultObj() != null){
            //获取Redis中的验证码记录
            String lastSendSmsCodeVoJson = smsCodelLastAjaxResult.getResultObj().toString();//JSON
            SendSmsCodeVo sendSmsCodeVo = JSON.parseObject(lastSendSmsCodeVoJson, SendSmsCodeVo.class);

            // 3.1.如果有，判断上一次发送时间和当前次发送时间是否过了60s
            //获取上一次发送时间
            Date lastSendTime = sendSmsCodeVo.getSendTime();
            if((now.getTime() - lastSendTime.getTime())/1000 < 60 ){
                throw new RuntimeException("发送频繁，请稍后重试");
            }
            //就不要创建验证码，把上一次的验证码
            smsCodeValue = sendSmsCodeVo.getSmsCode();
        }else{
            // 3.2.如果redis没有验证码,后端生成手机验证码
            smsCodeValue = StrUtils.getRandomString(4);
        }

        // 4.把手机验证码发送记录存储到Redis ：
        //把验证码发送记录封装成对象
        SendSmsCodeVo sendSmsCodeVo = new SendSmsCodeVo(smsCodeValue, now);
        //把对象转成JSON存储到Redis : fastjson
        String sendSmsCodeVoJson = JSON.toJSONString(sendSmsCodeVo);
        //这是一个覆盖的过程
        AjaxResult imageCodeResult = redisFeignClient.setex(smsCodeKey, imageCodeProperties.getTimeout(), sendSmsCodeVoJson);
        if(!imageCodeResult.isSuccess()){
            throw new RuntimeException("验证码发送失败[缓存服务不可用]");
        }

        //5.把验证码的内容进行发送到用户的手机：短信网关
        String messsage = "您的手机验证码为["+smsCodeValue+"]，请在5分钟内使用";
        //System.out.println(messsage);
        //填写必须的参数
        Map<String, String> params = new HashMap<>();
        params.put("Uid","zhangbaozhong");
        params.put("Key","1d41d8cd98f00b204e980");
        params.put("smsMob",mobile);
        params.put("smsText",messsage);

        HttpUtil.sendPost("http://utf8.api.smschinese.cn/",params);
        //6.Mysql存储发送记录
    }
}
